/*+***********************************************************************************
 Filename: 03_mcu_sparrowrvcore_02\src\top.v
 Description:
   a mcu framework with core from sparrowrv, bus and peripheral from A01_tinyriscv_mcu01 of tangnano9k,
   32k rom, 16k ram. 
   JTAG access rom, ram and peripheral through bus arbiter.
   Core access rom and ram directly, and access peripheral through bus arbiter.

 Modification:
(A01_tinyriscv_mcu01):
   2023.12.23 Creation   H.Zheng
   2024.01.07 modify jtag clk
   2024.02.05 copy and modified from A01_tinyriscv_step02   H.Zheng
              remove rom2
   2024.02.06 modify mux_2x3, change rom to 32k
   2024.02.07 change ram&rom clk to ~core_clk
   2024.02.08 peripheral add clk_1MHz, int_flag
(03_mcu_sparrowrvcore_01):
   2024.03.07 change core to sparrowrv H.Zheng
              and change module to tangprimer20k
(03_mcu_sparrowrvcore_02):
   2024.05.17 add core_loadstore_wmask
              change I_ROM to 64k DPB IP
              replace D_RAM with sram from sparrowrv and connect to bus 
   2024.05.19 change I_ROM&D_RAM's clk to ~core_clk
              

Copyright (C) 2024  Zheng Hui (hzheng@gzhu.edu.cn)

License: MulanPSL-2.0

***********************************************************************************-*/

module top(
  input wire sys_clk,     //27MHz
  input wire reset_n,
  input wire jtag_reset_n,
  //jtag
  input wire jtag_TCK,
  input wire jtag_TMS,
  input wire jtag_TDI,
  output wire jtag_TDO, 
  //peripheral: led, button and uart
  output wire [5:0] led,
  input wire [2:0] button,
  input wire uart0_rxd,
  output wire uart0_txd

/*
  //peripheral: ethernet
  output wire ety_phyrst,
  input netrmii_clk50m,
  input netrmii_rx_crs,
  output netrmii_mdc,
  output netrmii_txen,
  inout netrmii_mdio,
  output [1:0] netrmii_txd,
  input [1:0] netrmii_rxd,
  //peripheral: digital mic
  output wire mic_ws,
  output wire mic_ck,
  output wire mic_lr,
  input wire mic_data,
  //peripheral: dac headphone
  output wire dac_ws,
  output wire dac_bck,
  output wire dac_data,
  output wire dac_pa_en
*/
);

  //PLL
  wire clk_108MHz;
  Gowin_rPLL m_pll(
    .clkout(clk_108MHz), //output clkout
    .clkin(sys_clk) //input clkin
  );


  //core clk
  reg [26:0] counter;

  always @(posedge clk_108MHz) begin
      counter <= counter + 1'b1;
  end

//    wire core_clk = counter[0]; //54MHz  //not work
//    wire core_clk = counter[1]; //27MHz
//    wire core_clk = counter[3]; //6.25MHz
  wire core_clk = counter[2]; //13.5MHz
//    wire core_clk = counter[26]; //1Hz

//
  //jtag clk
  reg [5:0] jtagclk_counter;
  reg clk_1MHz;

  always @(posedge clk_108MHz) begin
    if (jtagclk_counter >=6'd53) begin
      jtagclk_counter <= 0;
      clk_1MHz <= ~clk_1MHz;
    end
    else begin
      jtagclk_counter <= jtagclk_counter + 1'b1;
    end
  end

  //jtag port
  wire jtag_halt_req_o;
  wire jtag_reset_req_o;
  wire[`RegAddrBus] jtag_reg_addr_o;
  wire[`RegBus] jtag_reg_data_o;
  wire jtag_reg_we_o;
  wire[`RegBus] jtag_reg_data_i;
  wire jtag_mem_we_o;
  wire [31:0] jtag_mem_addr_o;    
  wire [31:0] jtag_mem_data_i;
  wire [31:0] jtag_mem_data_o;
  wire jtag_debug_req;

  // tinyriscv port
  wire int_flag;
  wire rib_hold_flag_o;

  wire [31:0] ibus_addr;
  wire [31:0] instruction;
  wire [31:0] core_loadstore_addr;
  wire [31:0] core_loadstore_data_in;
  wire [31:0] core_loadstore_data_out;
  wire core_loadstore_ce;
  wire core_loadstore_we;
  wire [3:0] core_loadstore_wmask;

  wire hx_valid;
  wire soft_rst;

  core m_core(
    .clk(core_clk),
    .rst_n(reset_n),
    .core_loadstore_addr(core_loadstore_addr),
    .core_loadstore_data_in(core_loadstore_data_in),
    .core_loadstore_data_out(core_loadstore_data_out),
    .core_loadstore_ce(core_loadstore_ce),
    .core_loadstore_we(core_loadstore_we),
    .core_loadstore_wmask(core_loadstore_wmask),

    .ibus_addr(ibus_addr),
    .instruction(instruction),

    .halt_req_i(jtag_halt_req_o),

    .hx_valid(hx_valid),
    .soft_rst(soft_rst),
    .core_ex_trap_valid(int_flag),
    .core_ex_trap_ready()
 );


  // jtag模块例化
  jtag_top #(
    .DMI_ADDR_BITS(6),
    .DMI_DATA_BITS(32),
    .DMI_OP_BITS(2)
  ) u_jtag_top(
    .clk(clk_1MHz),
    .jtag_rst_n(jtag_reset_n),
    .jtag_pin_TCK(jtag_TCK),
    .jtag_pin_TMS(jtag_TMS),
    .jtag_pin_TDI(jtag_TDI),
    .jtag_pin_TDO(jtag_TDO),
    .reg_we_o(jtag_reg_we_o),
    .reg_addr_o(jtag_reg_addr_o),
    .reg_wdata_o(jtag_reg_data_o),
    .reg_rdata_i(32'b0),
    .mem_we_o(jtag_mem_we_o),
    .mem_addr_o(jtag_mem_addr_o),
    .mem_wdata_o(jtag_mem_data_o),
    .mem_rdata_i(jtag_mem_data_i),
    .op_req_o(jtag_debug_req),
    .halt_req_o(jtag_halt_req_o),
    .reset_req_o(jtag_reset_req_o)
  );

//Memory part

//rom address in bytes = [0x0???0000-0x0???ffff]: 64kBytes
//ram address in bytes  = [0x2???0000-0x2???3fff]: 16kBytes
//peripheral address    = [0x1???0000-0x1???3fff]: 16kBytes



  //bus mux

  wire[31:0] d0_addr_o, d1_addr_o, d2_addr_o;
  wire[31:0] d0_data_o, d1_data_o, d2_data_o;
  wire[31:0] d0_data_i, d1_data_i, d2_data_i;
  wire[3:0] d2_wmask_o;

//  mux_2x3 u_mux(
  mux_wmask_2x3 u_mux(
    // host 0 interface
    .h0_addr_i(jtag_mem_addr_o),
    .h0_data_i(jtag_mem_data_o),
    .h0_data_o(jtag_mem_data_i),
    .h0_req_i(jtag_debug_req),
    .h0_we_i(jtag_mem_we_o),

    // host 1 interface: connect to core's load-store bus sub2
    .h1_addr_i(core_loadstore_addr),
    .h1_data_i(core_loadstore_data_out),
    .h1_data_o(core_loadstore_data_in),
    .h1_req_i(core_loadstore_ce),
    .h1_we_i(core_loadstore_we),
    .h1_wmask_i(core_loadstore_wmask),

    // device 0 interface: to rom
    .d0_addr_o(d0_addr_o),
    .d0_data_o(d0_data_o),
    .d0_data_i(d0_data_i),
    .d0_we_o(d0_we_o),
    .d0_ce_o(d0_ce_o),

    // device 1 interface: to peripheral
    .d1_addr_o(d1_addr_o),
    .d1_data_o(d1_data_o),
    .d1_data_i(d1_data_i),
    .d1_we_o(d1_we_o),
    .d1_ce_o(d1_ce_o),

    // device 2 interface: to ram
    .d2_addr_o(d2_addr_o),
    .d2_data_o(d2_data_o),
    .d2_data_i(d2_data_i),
    .d2_we_o(d2_we_o),
    .d2_wmask_o(d2_wmask_o),
    .d2_ce_o(d2_ce_o),

    //core hold flag
    .h1_hold_flag_o(rib_hold_flag_o)
//        .h1_hold_flag_o()
  );

  // rom模块例化
  Gowin_DPB_64kB I_ROM(
    .douta(d0_data_i), //output [31:0] douta
    .doutb(instruction), //output [31:0] doutb
//    .clka(clk_108MHz), //input clka
    .clka(~core_clk), //input clka
    .ocea(1'b1), //input ocea
    .cea(d0_ce_o), //input cea
    .reseta(~jtag_reset_n), //input reseta
    .wrea(d0_we_o), //input wrea
//    .clkb(clk_108MHz), //input clkb
    .clkb(~core_clk), //input clkb
    .oceb(1'b1), //input oceb
    .ceb(1'b1), //input ceb
    .resetb(~reset_n), //input resetb
    .wreb(1'b0), //input wreb
    .ada(d0_addr_o[15:2]), //input [13:0] ada
    .dina(d0_data_o), //input [31:0] dina
    .adb(ibus_addr[15:2]), //input [13:0] adb
    .dinb(32'b0) //input [31:0] dinb
  );


sram D_RAM (
//    .clk              (clk_108MHz),
    .clk              (~core_clk),
    .rst_n            (reset_n),
    .sram_icb_cmd_valid (d2_ce_o),
    .sram_icb_cmd_ready (),
    .sram_icb_cmd_addr  (d2_addr_o ),
    .sram_icb_cmd_read  (~d2_we_o ),
    .sram_icb_cmd_wdata (d2_data_o),
//    .sram_icb_cmd_wmask (4'b1111),
    .sram_icb_cmd_wmask (d2_wmask_o),
    .sram_icb_rsp_valid (),
    .sram_icb_rsp_ready (1'b1),
    .sram_icb_rsp_err   (  ),
    .sram_icb_rsp_rdata (d2_data_i)
);


    //peripherals
    wire [5:0] peri_led;
    wire peri_txd;    

    peripheral m_peripheral(
        .clk(~core_clk),
        .clk_1MHz(clk_1MHz),
        .reset_n(reset_n),
        .button(button),
        .led(peri_led),
        .rxd(uart0_rxd),
        .txd(uart0_txd),
        //
        .ce(d1_ce_o),
        .wre(d1_we_o),
        .addr(d1_addr_o[13:2]),
        .data_in(d1_data_o),
        .data_out(d1_data_i),
        //
        .int_flag(int_flag)
    );


    //output
    assign led = peri_led; 


endmodule